﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using CrateMayhem.Common.Model;

namespace CrateMayhem.Common.Data
{
    public abstract class SettingsRepositoryBase : ISettingsRepository
    {
        private readonly XDocument document;

        protected SettingsRepositoryBase()
        {
            var properties = Properties;

            if (!properties.ContainsKey("Levels"))
            {
                document = new XDocument(new XElement("levels"));
                properties.Add("Levels", document.ToString());
            }
            else
            {
                var levels = (string)properties["Levels"];
                document = XDocument.Parse(levels);
            }
        }

        protected abstract IDictionary<string, object> Properties { get; }

        public ControlsLocationType GetControlsLocation()
        {
            var properties = Properties;

            if (!properties.ContainsKey("ControlsLocation"))
            {
                properties.Add("ControlsLocation", ControlsLocationType.Right.ToString());
                Save();
            }

            return (ControlsLocationType)Enum.Parse(
                typeof(ControlsLocationType), Properties["ControlsLocation"].ToString(), true);
        }

        public void ToggleControlsLocaton()
        {
            var current = GetControlsLocation();
            var newLayout = current == ControlsLocationType.Left 
                ? ControlsLocationType.Right : ControlsLocationType.Left;
            Properties["ControlsLocation"] = newLayout.ToString();
            Save();
        }

        public int FindLastCompletedLevel()
        {
            if (!document.Descendants("level").Any()) return 0;

            var levelElement = document
                .Descendants("level")
                .LastOrDefault(l => l.Attribute("completed") != null 
                    && l.Attribute("completed").Value == bool.TrueString);

            return levelElement != null ? int.Parse(levelElement.Attribute("id").Value) : 0;
        }

        public void ResetLevels()
        {
            Properties.Remove("Levels");
            Save();
        }

        public void Complete(int level, string moves)
        {
            var levelElement = FindLevelElement(level);
            levelElement.Attribute("moves").Value = moves.Length.ToString();

            var completedAttr = levelElement.Attribute("completed");

            if (completedAttr == null)
                levelElement.Add(new XAttribute("completed", bool.TrueString));
            else
                completedAttr.Value = bool.TrueString;

            Properties["Levels"] = document.ToString(SaveOptions.DisableFormatting);
            Save();
        }

        protected virtual void Save()
        {
        }

        private XElement FindLevelElement(int level)
        {
            var levelElements = document.Descendants("level");
            var levelElement = levelElements.FirstOrDefault(l => int.Parse(l.Attribute("id").Value) == level);

            if (levelElement == null)
            {
                levelElement = new XElement(
                    "level",
                    new XAttribute("id", level),
                    new XAttribute("moves", 0));
                document.Element("levels").Add(levelElement);
            }

            return levelElement;
        }
    }
}